package com.yejiarong.weather.common.exception;

import com.yejiarong.common.exception.GlobalException;
import com.yejiarong.common.exception.ResponseCode;
import com.yejiarong.common.tools.HttpResult;
import feign.FeignException;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.util.StreamUtils;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

/**
 * @author YeJR
 */
@Slf4j
@RestControllerAdvice
public class DefaultExceptionHandler {

    /**
     * Feign拦截解析
     * @param e 异常
     * @return HttpResult
     */
    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler({FeignException.class})
    public HttpResult<Void> handle(FeignException e, HttpServletRequest request) {
        printRequestDetails(request);
        log.error("Feign异常错误: ", e);
        return HttpResult.error(ResponseCode.SERVER_ERROR.getCode(), ResponseCode.SERVER_ERROR.getDefaultMessage());
    }

    /**
     * 自定义异常拦截
     * @param e 异常
     * @return HttpResult
     */
    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler(GlobalException.class)
    public HttpResult<Void> handle(GlobalException e, HttpServletRequest request) {
        printRequestDetails(request);
        log.error("自定义异常", e);
        return HttpResult.error(e.getCode(), e.getMessage());
    }

    /**
     * 运行时异常拦截
     * @param e 异常
     * @param request request
     * @return HttpResult
     */
    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler(RuntimeException.class)
    public HttpResult<Void> handle(RuntimeException e, HttpServletRequest request) {
        printRequestDetails(request);
        log.error("未知异常", e);
        return HttpResult.error(ResponseCode.SERVER_ERROR.getCode(), ResponseCode.SERVER_ERROR.getDefaultMessage());
    }


    /**
     * 打印请求信息
     * @param request  request
     */
    protected void printRequestDetails(HttpServletRequest request) {
        try {
            String requestURL = request.getRequestURL().toString();
            String method = request.getMethod();
            Map<String, String> headers = getHeadersInfo(request);
            Map<String, String> parameterMap = getParameterInfo(request);
            String requestBody = getRequestBody(request);
            log.error(System.lineSeparator() +
                    ">>>>>>>>>>>>>>Request Detail>>>>>>>>>>>>>> " + System.lineSeparator() +
                    " URL: {} "+ System.lineSeparator() +
                    " Method: {} "+ System.lineSeparator() +
                    " Headers: {} "+ System.lineSeparator() +
                    " Parameters: {} "+ System.lineSeparator() +
                    " Body: {}"+ System.lineSeparator() +
                    "<<<<<<<<<<<<<<Request Detail<<<<<<<<<<<<<<",
                    requestURL,
                    method,
                    headers,
                    parameterMap,
                    requestBody );
        } catch (Exception e) {
            log.error("Exception occurred during request processing", e);
        }
    }

    /**
     * request 信息
     * @param request request
     * @return Map
     */
    protected Map<String, String> getParameterInfo(HttpServletRequest request) {
        Map<String, String> parameters = new HashMap<>();
        Map<String, String[]> parameterMap = request.getParameterMap();
        for (Map.Entry<String, String[]> entry : parameterMap.entrySet()) {
            parameters.put(entry.getKey(), String.join(",", entry.getValue()));
        }
        return parameters;
    }

    /**
     * head 信息
     * @param request request
     * @return Map
     */
    protected Map<String, String> getHeadersInfo(HttpServletRequest request) {
        Map<String, String> headers = new HashMap<>();
        Enumeration<String> headerNames = request.getHeaderNames();
        while(headerNames.hasMoreElements()) {
            String headerName = headerNames.nextElement();
            headers.put(headerName, request.getHeader(headerName));
        }
        return headers;
    }

    /**
     * 请求体
     * @param request request
     * @return String
     */
    protected String getRequestBody(HttpServletRequest request) {
        try {
            String requestBody = StreamUtils.copyToString(request.getInputStream(), StandardCharsets.UTF_8);
            requestBody = requestBody.replaceAll("\n", "").replaceAll("\r", "").replaceAll(" ", "");
            return requestBody;
        } catch (IOException e) {
            log.error("Failed to read request body", e);
        }
        return "";
    }
}
